//-----------------------------------------------
//    module name: routeMsg 
//    author: Anping HE (heap@lzu.edu.cn)
//  modifier: Fu Tong , Baoxia Wan , Mingshu Chen ,Kang Li Zhao
//    version: 2st version (2021-11-17)
//    description: 
//        routing message 
//        have a lock mechanism that supports any cases
//-----------------------------------------------

`timescale 1ns / 1ps

module routeMsg(
    inR, inA, rst,
    i_msg_51,
    localOutR, localOutA, o_localMsg_51,
    westOutR, westOutA, o_westMsg_51,
    eastOutR, eastOutA, o_eastMsg_51,
    southOutR, southOutA, o_southMsg_51,
    northOutR, northOutA, o_northMsg_51 );

input inR, rst;
output inA;

input [50:0] i_msg_51;

output localOutR;
input localOutA;
output [50:0] o_localMsg_51;

output westOutR;
input westOutA;
output [50:0] o_westMsg_51;

output eastOutR;
input eastOutA;
output [50:0] o_eastMsg_51;

output northOutR;
input northOutA;
output [50:0] o_northMsg_51;

output southOutR;
input southOutA;
output [50:0] o_southMsg_51;


//---------------------------------------------------------
// inner regs and wires
wire[1:0] w_trunkFifoFire_2;
wire pmt;

wire[2:0] w_delayR_3;
wire[2:0] w_delayA_3;

wire tapLocal;
wire w_localFire_1;
wire tapWest;
wire w_westFire_1;
wire tapEast;
wire w_eastFire_1;
wire tapNorth;
wire w_northFire_1;
wire tapSouth;
wire w_southFire_1;

wire [50:0] w_eastTmpMsg_51;
wire [50:0] w_westTmpMsg_51;
wire [50:0] w_southTmpMsg_51;
wire [50:0] w_northTmpMsg_51;

wire [50:0] w_westMsg_51;     
wire [50:0] w_eastMsg_51;     
wire [50:0] w_northMsgPrio_51;   
wire [50:0] w_northMsg_51;   
wire [50:0] w_southMsgPrio_51;   
wire [50:0] w_southMsg_51;   

wire w_localVld_1;
wire w_westVld_1;     
wire w_eastVld_1;     
wire w_northVld_1;   
wire w_southVldNS_1;   
wire w_southVld_1;   
wire w_northVldSN_1;   

//wire [21:0] w_localMsgNS_22;   
//wire [21:0] w_localMsgSN_22;   
wire [40:0] w_localMsg_41;   
wire [50:0] w_localMsg_51;   


wire localTrig;
wire localIdle;
wire w_localIdleTmp_1;

wire westTrig;
wire westIdle;
wire w_westIdleTmp_1;

wire eastTrig;
wire eastIdle;
wire w_eastIdleTmp_1;

wire northTrig;
wire northIdle;
wire w_northIdleTmp_1;

wire southTrig;
wire southIdle;
wire w_southIdleTmp_1;


reg [50:0] r_localMsg_51;
reg [50:0] r_westMsg_51;
reg [50:0] r_eastMsg_51;
reg [50:0] r_northMsg_51;
reg [50:0] r_southMsg_51;

wire inANon;

wire localArbDone;
wire localDoneANon;
wire localDoneR_1;
wire localDoneA_1;
wire localDoneFire;
wire localPmt;
wire eastArbDone;
wire eastDoneANon;
wire eastDoneR_1;
wire eastDoneA_1;
wire eastDoneFire;
wire eastPmt;
wire westArbDone;
wire westDoneANon;
wire westDoneR_1;
wire westDoneA_1;
wire westDoneFire;
wire westPmt;
wire northArbDone;
wire northDoneANon;
wire northDoneR_1;
wire northDoneA_1;
wire northDoneFire;
wire northPmt;
wire southArbDone;
wire southDoneANon;
wire southDoneR_1;
wire southDoneA_1;
wire southDoneFire;
wire southPmt;
//---------------------------------------------------------
//trunk fifo

posClick trunkFifo0(
    .inR(inR), 
    .inA(inANon), 
    .outR(w_delayR_3[0]), 
    .outA(w_delayA_3[0]), 
    .fire(w_trunkFifoFire_2[0]), 
    .rst(rst) );
bidirDelay10U delay0(
    .inR(w_delayR_3[0]), 
    .inA(w_delayA_3[0]), 
    .outR(w_delayR_3[1]), 
    .outA(w_delayA_3[1]) );
posClick trunkFifo1(
    .inR(w_delayR_3[1]), 
    .inA(w_delayA_3[1]), 
    .outR(w_delayR_3[2]), 
    .outA(w_delayA_3[2]), 
    .fire(w_trunkFifoFire_2[1]), 
    .rst(rst) );
pmtSink trunkPmt(
    //.trig(delayPmt),
    .trig(pmt),
    .inR(w_delayR_3[2]), 
    .inA(w_delayA_3[2]), 
    .rst(rst) );

assign inA = w_delayA_3[2];
//---------------------------------------------------------
//branch fifo
wire w_localInANon_1;
wire w_westInANon_1;
wire w_eastInANon_1;
wire w_northInANon_1;
wire w_southInANon_1;

//local branch
contTap localContTap(
    .trig(localTrig),
    .req(tapLocal),
    .rst(rst) );
posClick localFifo(
    .inR(tapLocal), 
    .inA(w_localInANon_1), 
    .outR(localOutR), 
    .outA(localOutA), 
    .fire(w_localFire_1), 
    .rst(rst) );

negClick localfifo0(
    .inR(localArbDone), 
    .inA(localDoneANon), 
    .outR(localDoneR_1), 
    .outA(localDoneA_1), 
    .fire(localDoneFire), 
    .rst(rst) 
    ); 
natSink localnat(
    .inR(localDoneR_1),
    .inA(localDoneA_1)
);
assign localArbDone=~(tapLocal^localOutA);
assign localPmt=localArbDone&localDoneFire;
//west branch
contTap westContTap(
    .trig(westTrig),
    .req(tapWest),
    .rst(rst) );
posClick westFifo(
    .inR(tapWest), 
    .inA(w_westInANon_1), 
    .outR(westOutR), 
    .outA(westOutA), 
    .fire(w_westFire_1), 
    .rst(rst) );

negClick westfifo0(
    .inR(westArbDone), 
    .inA(westDoneANon), 
    .outR(westDoneR_1), 
    .outA(westDoneA_1), 
    .fire(westDoneFire), 
    .rst(rst) 
    ); 
natSink westnat(
    .inR(westDoneR_1),
    .inA(westDoneA_1)
);
assign westArbDone=~(tapWest^westOutA);
assign westPmt=westArbDone&westDoneFire;
//east branch
contTap eastContTap(
    .trig(eastTrig),
    .req(tapEast),
    .rst(rst) );
posClick eastFifo(
    .inR(tapEast), 
    .inA(w_eastInANon_1), 
    .outR(eastOutR), 
    .outA(eastOutA), 
    .fire(w_eastFire_1), 
    .rst(rst) );

negClick eastfifo0(
    .inR(eastArbDone), 
    .inA(eastDoneANon), 
    .outR(eastDoneR_1), 
    .outA(eastDoneA_1), 
    .fire(eastDoneFire), 
    .rst(rst) 
    ); 
natSink eastnat(
    .inR(eastDoneR_1),
    .inA(eastDoneA_1)
);
assign eastArbDone=~(tapEast^eastOutA);
assign eastPmt=eastArbDone&eastDoneFire;
//north branch
contTap northContTap(
    .trig(northTrig),
    .req(tapNorth),
    .rst(rst) );
posClick northFifo(
    .inR(tapNorth), 
    .inA(w_northInANon_1), 
    .outR(northOutR), 
    .outA(northOutA), 
    .fire(w_northFire_1), 
    .rst(rst) );

negClick northfifo0(
    .inR(northArbDone), 
    .inA(northDoneANon), 
    .outR(northDoneR_1), 
    .outA(northDoneA_1), 
    .fire(northDoneFire), 
    .rst(rst) 
    ); 
natSink northnat(
    .inR(northDoneR_1),
    .inA(northDoneA_1)
);
assign northArbDone=~(tapNorth^northOutA);
assign northPmt=northArbDone&northDoneFire;
//south branch
contTap southContTap(
    .trig(southTrig),
    .req(tapSouth),
    .rst(rst) );
posClick southFifo(
    .inR(tapSouth), 
    .inA(w_southInANon_1), 
    .outR(southOutR), 
    .outA(southOutA), 
    .fire(w_southFire_1), 
    .rst(rst) );

negClick southfifo0(
    .inR(southArbDone), 
    .inA(southDoneANon), 
    .outR(southDoneR_1), 
    .outA(southDoneA_1), 
    .fire(southDoneFire), 
    .rst(rst) 
    ); 
natSink southnat(
    .inR(southDoneR_1),
    .inA(southDoneA_1)
);
assign southArbDone=~(tapSouth^southOutA);
assign southPmt=southArbDone&southDoneFire;
//---------------------------------------------------------
//input message
(* dont_touch = "true" *)reg [50:0] r_msg_51;
always@(posedge w_trunkFifoFire_2[0] or negedge rst)
begin
    if(!rst)
        r_msg_51 <= 51'b0;
    else 
        r_msg_51<= i_msg_51;
end



//---------------------------------------------------------
//calculate the direction
//    first check local, east->west and west->east parallelly, 
//        (not involved) get local msg, or
//        get east or west message, or
//        get south_north message (possibly be zero);
//    then if south_north message not be zero,
//        check south->north and north->south parallely,
//        get south or north message
//    e.g., the priority is:
//        {east, west} > {south, north} > {local}
wire r_9;
inv v0(r_msg_51[9],r_9);
wire r_4;
inv v1(r_msg_51[4],r_4);
//get east->west info
assign    w_eastTmpMsg_51 = (r_9==0) ? r_msg_51 : 51'b0;

routeMsgEW eastToWest(
    .i_msg_51(w_eastTmpMsg_51),
    .i_coord_4(w_eastTmpMsg_51[8:5]),
    .o_msg_51(w_westMsg_51),
    .o_msgVld_1(w_westVld_1) );

//get west->east info
assign w_westTmpMsg_51 = (r_9==1) ? r_msg_51 : 51'b0;

routeMsgEW westToEast(
    .i_msg_51(w_westTmpMsg_51),
    .i_coord_4(w_westTmpMsg_51[8:5]),
    .o_msg_51(w_eastMsg_51),
    .o_msgVld_1(w_eastVld_1) );

//get south->north info
assign w_southTmpMsg_51 = (r_4==1)? r_msg_51 : 51'b0;

routeMsgSN southToNorth(
    .i_msg_51(w_southTmpMsg_51),
    .i_coord_4(w_southTmpMsg_51[3:0]),
    .o_msg_51(w_northMsgPrio_51),
    .o_msgVld_1(w_northVldSN_1) );
assign w_northMsg_51 = ((r_4==1) & ~(w_eastVld_1 | w_westVld_1)) ? w_northMsgPrio_51 : 51'b0;
assign w_northVld_1 = w_northVldSN_1 & ~(w_eastVld_1 | w_westVld_1);

//get north->south info
assign    w_northTmpMsg_51 = (r_4==0) ? r_msg_51 : 51'b0;

routeMsgSN northToSouth(
    .i_msg_51(w_northTmpMsg_51),
    .i_coord_4(w_northTmpMsg_51[3:0]),
    .o_msg_51(w_southMsgPrio_51),
    .o_msgVld_1(w_southVldNS_1) );
assign w_southMsg_51 = ((r_4==0) & ~(w_eastVld_1 | w_westVld_1)) ? w_southMsgPrio_51 : 51'b0;
assign w_southVld_1 = w_southVldNS_1 & ~(w_eastVld_1 | w_westVld_1);

//get local info

assign w_localVld_1 = 
    ~(w_westVld_1 | 
    w_eastVld_1 | 
    w_southVld_1 | 
    w_northVld_1);
assign w_localMsg_41 = (w_localVld_1==1) ? r_msg_51[50:10] : 41'b0;
assign w_localMsg_51 = {w_localMsg_41,10'b0};


//---------------------------------------------------------
//make decision 
//local
assign localTrig = w_trunkFifoFire_2[1] & w_localVld_1;
//contTap localIdleTap(
//    .trig(pmt),
//    .req(w_localIdleTmp_1),
//    .rst(rst) );
//assign localIdle =  ~w_localIdleTmp_1;

//west
assign westTrig = w_trunkFifoFire_2[1] & w_westVld_1;
//contTap westIdleTap(
//    .trig(pmt),
//    .req(w_westIdleTmp_1),
//    .rst(rst) );
//assign westIdle = ~w_westIdleTmp_1;

//east
assign eastTrig = w_trunkFifoFire_2[1] & w_eastVld_1;
//contTap eastIdleTap(
//    .trig(pmt),
//    .req(w_eastIdleTmp_1),
//    .rst(rst) );
//assign eastIdle = ~w_eastIdleTmp_1;

//north 
assign northTrig = w_trunkFifoFire_2[1] & w_northVld_1;
//contTap northIdleTap(
//    .trig(pmt),
//    .req(w_northIdleTmp_1),
//    .rst(rst) );
//assign northIdle = ~w_northIdleTmp_1;

//south
assign southTrig = w_trunkFifoFire_2[1] & w_southVld_1;
//contTap southIdleTap(
//    .trig(pmt),
//    .req(w_southIdleTmp_1),
//    .rst(rst) );
//assign southIdle = ~w_southIdleTmp_1;


//assign pmt = westTrig | eastTrig | northTrig | southTrig | localTrig;

assign pmt = westPmt | eastPmt | northPmt | southPmt | localPmt;
//delay1U delay9(.inR(pmt), .outR(delayPmt));
//---------------------------------------------------------
//generate output message
//local
always@(posedge w_localFire_1 or negedge rst)
begin
    if(!rst) begin
        r_localMsg_51 <= 51'b0;
        end
    else begin
        r_localMsg_51 <= w_localMsg_51;
        end
end

//west
always@(posedge w_westFire_1 or negedge rst)
begin
    if(!rst) begin
        r_westMsg_51 <= 51'b0;
        end
    else begin
        r_westMsg_51 <=  w_westMsg_51;
        end
end

//east
always@(posedge w_eastFire_1 or negedge rst)
begin
    if(!rst) begin
        r_eastMsg_51 <= 51'b0;
        end
    else begin
        r_eastMsg_51 <=  w_eastMsg_51;
        end
end    

//north
always@(posedge w_northFire_1 or negedge rst)
begin
    if(!rst) begin
         r_northMsg_51 <= 51'b0;
        end
    else begin
        r_northMsg_51 <= w_northMsg_51;
        end
end         

//south
always@(posedge w_southFire_1 or negedge rst)
begin
    if(!rst) begin
        r_southMsg_51 <= 51'b0;
        end
    else begin
        r_southMsg_51 <= w_southMsg_51;
        end
end           
        
assign o_localMsg_51 = r_localMsg_51;
assign o_westMsg_51 = r_westMsg_51;
assign o_eastMsg_51 = r_eastMsg_51;
assign o_northMsg_51 = r_northMsg_51;
assign o_southMsg_51 = r_southMsg_51;



endmodule
